#!/usr/bin/env python3
"""
I2C-24C02 读写实验平台 - 后端服务
模拟I2C总线协议和24C02 EEPROM读写操作
"""

from flask import Flask, render_template, request, jsonify
import json
import time
import threading
from datetime import datetime

app = Flask(__name__)

# 全局变量
eeprom_data = [0xFF] * 256  # 24C02有256字节存储空间
i2c_log = []
device_address = 0x50  # 默认24C02地址
write_protected = False
waveform_data = []

class I2CSimulator:
    """I2C总线协议模拟器"""
    
    def __init__(self):
        self.scl = 1  # 时钟线
        self.sda = 1  # 数据线
        self.start_time = time.time()
        
    def log_event(self, event, scl=None, sda=None):
        """记录I2C事件"""
        if scl is not None:
            self.scl = scl
        if sda is not None:
            self.sda = sda
            
        timestamp = time.time() - self.start_time
        log_entry = {
            'time': timestamp,
            'event': event,
            'scl': self.scl,
            'sda': self.sda
        }
        i2c_log.append(log_entry)
        
        # 记录波形数据
        waveform_data.append({
            'time': timestamp,
            'scl': self.scl,
            'sda': self.sda
        })
        
    def start_condition(self):
        """产生起始条件"""
        self.log_event("Start", scl=1, sda=1)
        self.log_event("Start", scl=1, sda=0)
        self.log_event("Start", scl=0, sda=0)
        
    def stop_condition(self):
        """产生停止条件"""
        self.log_event("Stop", scl=0, sda=0)
        self.log_event("Stop", scl=1, sda=0)
        self.log_event("Stop", scl=1, sda=1)
        
    def write_bit(self, bit):
        """写入一个比特"""
        self.log_event(f"Write bit {bit}", scl=0, sda=bit)
        self.log_event(f"Write bit {bit}", scl=1, sda=bit)
        self.log_event(f"Write bit {bit}", scl=0, sda=bit)
        
    def read_bit(self):
        """读取一个比特"""
        self.log_event("Read bit", scl=0, sda=1)
        self.log_event("Read bit", scl=1, sda=1)
        bit = 1  # 模拟读取
        self.log_event(f"Read bit {bit}", scl=0, sda=bit)
        return bit
        
    def write_byte(self, byte):
        """写入一个字节"""
        for i in range(8):
            bit = (byte >> (7 - i)) & 1
            self.write_bit(bit)
            
    def read_byte(self):
        """读取一个字节"""
        byte = 0
        for i in range(8):
            bit = self.read_bit()
            byte = (byte << 1) | bit
        return byte
        
    def send_ack(self, ack):
        """发送ACK/NAK"""
        self.log_event(f"ACK {ack}", scl=0, sda=0 if ack else 1)
        self.log_event(f"ACK {ack}", scl=1, sda=0 if ack else 1)
        self.log_event(f"ACK {ack}", scl=0, sda=0 if ack else 1)

i2c = I2CSimulator()

@app.route('/')
def index():
    """主页路由"""
    return render_template('index.html')

@app.route('/api/write', methods=['POST'])
def write_eeprom():
    """写入EEPROM数据"""
    global eeprom_data, write_protected
    
    data = request.json
    address = data.get('address', 0)
    values = data.get('values', [])
    
    if write_protected:
        return jsonify({'error': '写保护已启用'}), 400
        
    if address < 0 or address > 255:
        return jsonify({'error': '地址超出范围'}), 400
        
    if not isinstance(values, list):
        values = [values]
        
    # 模拟I2C写入过程
    i2c.start_condition()
    
    # 发送器件地址和写标志
    device_addr = (device_address << 1) | 0
    i2c.write_byte(device_addr)
    i2c.send_ack(True)
    
    # 发送内存地址
    i2c.write_byte(address)
    i2c.send_ack(True)
    
    # 写入数据
    for value in values:
        if address > 255:
            break
        eeprom_data[address] = value & 0xFF
        i2c.write_byte(value & 0xFF)
        i2c.send_ack(True)
        address += 1
        
    i2c.stop_condition()
    
    return jsonify({
        'success': True,
        'bytes_written': len(values),
        'log': i2c_log[-20:]  # 返回最近20条日志
    })

@app.route('/api/read', methods=['POST'])
def read_eeprom():
    """读取EEPROM数据"""
    global eeprom_data
    
    data = request.json
    address = data.get('address', 0)
    length = data.get('length', 1)
    
    if address < 0 or address > 255:
        return jsonify({'error': '地址超出范围'}), 400
        
    if length < 1 or length > 256:
        return jsonify({'error': '长度超出范围'}), 400
        
    # 模拟I2C读取过程
    i2c.start_condition()
    
    # 发送器件地址和写标志
    device_addr = (device_address << 1) | 0
    i2c.write_byte(device_addr)
    i2c.send_ack(True)
    
    # 发送内存地址
    i2c.write_byte(address)
    i2c.send_ack(True)
    
    # 重新启动以读取数据
    i2c.start_condition()
    
    # 发送器件地址和读标志
    device_addr = (device_address << 1) | 1
    i2c.write_byte(device_addr)
    i2c.send_ack(True)
    
    # 读取数据
    read_data = []
    for i in range(length):
        if address + i > 255:
            break
        byte = eeprom_data[address + i]
        read_data.append(byte)
        i2c.read_byte()
        i2c.send_ack(i < length - 1)  # 最后一个字节发送NAK
        
    i2c.stop_condition()
    
    return jsonify({
        'data': read_data,
        'hex': [f'0x{byte:02X}' for byte in read_data],
        'ascii': ''.join([chr(byte) if 32 <= byte <= 126 else '.' for byte in read_data]),
        'log': i2c_log[-20:]  # 返回最近20条日志
    })

@app.route('/api/config', methods=['POST'])
def update_config():
    """更新配置"""
    global device_address, write_protected
    
    data = request.json
    if 'device_address' in data:
        device_address = data['device_address'] & 0x7F
    if 'write_protected' in data:
        write_protected = data['write_protected']
        
    return jsonify({
        'device_address': device_address,
        'write_protected': write_protected
    })

@app.route('/api/status')
def get_status():
    """获取当前状态"""
    return jsonify({
        'eeprom_data': eeprom_data,
        'device_address': device_address,
        'write_protected': write_protected,
        'log': i2c_log[-50:],  # 返回最近50条日志
        'waveform': waveform_data[-100:]  # 返回最近100个波形点
    })

@app.route('/api/clear')
def clear_log():
    """清除日志"""
    global i2c_log, waveform_data
    i2c_log.clear()
    waveform_data.clear()
    return jsonify({'success': True})

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
